//
// File:    progform.cpp
// Brief:   测试程序编辑画面实现文件
//
// History:
// ============================================================================
// 2010-11-01    Finux Chen <finuxchen@gmail.com>    创建
// 2010-12-16    Finux Chen <finuxchen@gmail.com>    使用Interview模式重构
// 2011-01-20    Finux Chen <finuxchen@gmail.com>    使用core模块新接口
// 2011-02-18    Finux Chen <finuxchen@gmail.com>    
//               添加光量项目detail设定功能和item suffix相关处理
//
#include <QtGui>
#include "progform.h"
#include "progtableitem.h"
#include "progtabledelegate.h"
#include "loadprogdlg.h"
#include "devtypedlg.h"
#include "detaildlg.h"
#include "../core/aprcfg.h"
#include "../core/measprog.h"
#include "valuesettingsform.h"
#include "saveform.h"


const char *VERTICAL_HEADERS[] = { "item", /*"ch",*/ "bias", 
								   "b unit", "time", "meas l", 
						      	   "meas u", "m unit",
								   "fil", "limit", "judge",
								   "active" };

const int MAX_ITEM_KIND  = 16;

int ProgForm::chnCount = 1;

ProgForm::ProgForm(QWidget *parent)
	: QMdiSubWindow(parent)
{
	// =========================================================================
	// New Look with .ui files

	ui.setupUi(this);
	deviceCombo  = ui.devicecombo;
	comboItemSel = ui.itemCombo;
	btnDetail    = ui.detailButton;
	btnItemAdd   = ui.appendButton;
	btnItemIns   = ui.insertButton;
	btnItemDel   = ui.deleteButton;
	btnItemClr   = ui.clearButton;
	btnProgNew   = ui.newButton;
	btnProgSave  = ui.saveButton;
	table        = ui.tableWidget;
	backButton   = ui.backButton;

	QStringList deviceList;
	AprCfg::getNamesByAttr(PM_DEV_ATTR, deviceList);
	deviceCombo->addItems(deviceList);

	QStringList itemList;
	AprCfg::getNamesByAttr(PM_ITEM_ATTR, itemList);
	comboItemSel->addItems(itemList);
	
	table->setRowCount(PROG_TABLE_ROWS);
	table->setItemDelegate(new ProgTableDelegate);
	for(int r = 0; r < PROG_TABLE_ROWS; ++r){
		table->setVerticalHeaderItem(r, 
					new QTableWidgetItem(tr(VERTICAL_HEADERS[r])));
//		table->setRowHeight(r, 40);
	}
    table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::DoubleClicked);



	// hide old rows & display settings

//	table->horizontalHeader()->setEnabled(false);
//	table->verticalHeader()->setEnabled(false);
	for(int r = 0; r < PROG_TABLE_ROWS; ++r){
		table->setRowHeight(r, kRowHeight);
	}

	table->hideRow(ProgTableDelegate::PROG_TABLE_ROW_BIAS_UNIT);
	table->hideRow(ProgTableDelegate::PROG_TABLE_ROW_MEAS_U);
	table->hideRow(ProgTableDelegate::PROG_TABLE_ROW_MEAS_UNIT);
	table->hideRow(ProgTableDelegate::PROG_TABLE_ROW_ACTIVE);

	loadItems();

	// =========================================================================


/*
	//
	// Initialize controls
	//
	QStringList itemList;
	AprCfg::getNamesByAttr(PM_ITEM_ATTR, itemList);

	comboItemSel = new QComboBox;
	comboItemSel->addItems(itemList);
	comboItemSel->setFixedHeight(40);

	QStringList devList;
	QString		dev;
	AprCfg::getNamesByAttr(PM_DEV_ATTR, devList);
	dev = devList.at(0);
	btnDevType	= new QPushButton(dev);
//	btnDetail	= new QPushButton(tr("DETAIL SETTING"));
	btnDetail	= new QPushButton(tr("DETAIL"));
	btnItemAdd  = new QPushButton(tr("ADD ITEM"));
	btnItemIns	= new QPushButton(tr("INS ITEM"));
	btnItemDel  = new QPushButton(tr("DEL ITEM"));
	btnItemClr  = new QPushButton(tr("CLEAR ITEMS"));
	btnProgNew  = new QPushButton(tr("NEW PROG."));
	btnProgSave = new QPushButton(tr("SAVE PROG."));
	btnDevType->setFixedHeight(40);
	btnDetail->setFixedHeight(40);
	btnItemAdd->setFixedHeight(40);
	btnItemIns->setFixedHeight(40);
	btnItemDel->setFixedHeight(40);
	btnItemClr->setFixedHeight(40);
	btnProgNew->setFixedHeight(40);
	btnProgSave->setFixedHeight(40);

	table = new QTableWidget(PROG_TABLE_ROWS, 0);
	table->setItemDelegate(new ProgTableDelegate);
	for(int r = 0; r < PROG_TABLE_ROWS; ++r){
		table->setVerticalHeaderItem(r, 
					new QTableWidgetItem(VERTICAL_HEADERS[r]));
		table->setRowHeight(r, 40);
	}
    table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::DoubleClicked);
	
	//
	// Manage layouts & window style
	//
	QHBoxLayout *hlayout = new QHBoxLayout;
//	hlayout->addWidget(labelDevType);
	hlayout->addWidget(btnDevType);
	hlayout->addWidget(comboItemSel);
	hlayout->addWidget(btnItemAdd);
	hlayout->addWidget(btnItemIns);
	hlayout->addWidget(btnItemDel);
	hlayout->addWidget(btnItemClr);
	hlayout->addWidget(btnDetail);
	hlayout->addWidget(btnProgNew);
	hlayout->addWidget(btnProgSave);

	QVBoxLayout *vlayout = new QVBoxLayout;
	vlayout->addLayout(hlayout);
	vlayout->addWidget(table);

	QFrame *frame = new QFrame;
	frame->setLayout(vlayout);

	setWidget(frame);

*/
	// set font size
	QFont font = this->font();
	font.setPixelSize(font.pointSize() * 4 / 3);
	setFont(font);

	setWindowFlags(Qt::CustomizeWindowHint | Qt::FramelessWindowHint);
	showMaximized();

	//
	// Connect signals & slots
	//
	QObject::connect(btnItemAdd, SIGNAL(clicked()), this, SLOT(itemAdd()));
	QObject::connect(btnItemIns, SIGNAL(clicked()), this, SLOT(itemInsert()));
	QObject::connect(btnItemDel, SIGNAL(clicked()), this, SLOT(itemDelete()));
//	QObject::connect(btnDevType, SIGNAL(clicked()), this, SLOT(devTypeChanged()));
//	QObject::connect(btnProgSave, SIGNAL(clicked()), this, SLOT(saveProg2Shm()));
	connect(btnProgSave, SIGNAL(clicked()), this, SLOT(saveItems()));
	connect(btnItemClr, SIGNAL(clicked()), this, SLOT(clearItems()));
	connect(btnProgNew, SIGNAL(clicked()), this, SLOT(createProg()));
//	connect(btnDevType, SIGNAL(clicked()), this, SLOT(openDevTypeDlg()));
	connect(btnDetail, SIGNAL(clicked()), this, SLOT(detailSetting()));
//	connect(btnDevType, SIGNAL(clicked()), this, SLOT(loadItems()));
	connect(comboItemSel, SIGNAL(currentIndexChanged(const QString&)),
			this, SLOT(itemKindSel(const QString&)));
	connect(deviceCombo, SIGNAL(currentIndexChanged(const QString&)),
			this, SLOT(deviceTypeChanged(const QString&)));

	connect(table, SIGNAL(cellClicked(int, int)), this, SLOT(tableCellClicked(int, int)));
	//chnCount = 1;

	connect(backButton, SIGNAL(clicked()), this, SLOT(formShouldReturn()));

	memset(hueDetail, 0xff, sizeof(det_u)*MAX_ITEM_QTY);
}



ProgForm::~ProgForm()
{
	
	delete deviceCombo;
	delete comboItemSel;
	delete btnDetail;
	delete btnItemAdd;  
	delete btnItemIns; 
	delete btnItemDel; 
	delete btnItemClr; 
	delete btnProgNew; 
	delete btnProgSave; 
	delete backButton;  

	// TODO: confused!!!!
//	while(table->columnCount() > 0){
//		table->setCurrentCell(0, 0);
//		itemDelete();
//	}
	delete table;
}

//////////////////////////////////////////////////////////////////////////
///////// SLOTS


void ProgForm::tableCellClicked(int r, int c)
{
	QString item_suffix_ch = 
		table->item(ProgTableDelegate::PROG_TABLE_ROW_NAME , c)->text();
	int item_index = item_suffix_ch.indexOf(tr("_"));
	QString item = item_suffix_ch.left(item_index);
//	qDebug() << item;
	QString current_range;
	QString lower_value;
	QString upper_value;
	QString get_range, get_lower, get_upper, get_unit;
	ValueSettingsForm *vsf = NULL;
	QString left_string;
	QString channel_info;
	int	channel_no;

	if(ProgTableDelegate::PROG_TABLE_ROW_NAME == r){
		qDebug() << "name row clicked";
		channel_info = table->item(ProgTableDelegate::PROG_TABLE_ROW_NAME, c)->text();
		channel_info = channel_info.left(channel_info.indexOf(tr(")")));
		left_string  = channel_info.left(channel_info.length() - 1);
		channel_info = channel_info.right(1);
		channel_no	 = channel_info.toInt();
		++channel_no;
		if(channel_no > chnCount){
			channel_no = 1;
		}
		channel_info = left_string + QString::number(channel_no) + tr(")");
		table->item(ProgTableDelegate::PROG_TABLE_ROW_NAME, c)->setText(channel_info);
		

	}else if(ProgTableDelegate::PROG_TABLE_ROW_BIAS == r){
		current_range = 
			table->item(ProgTableDelegate::PROG_TABLE_ROW_BIAS_UNIT, c)->text();
		lower_value = table->item(r, c)->text();
		lower_value = lower_value.left(lower_value.indexOf(tr(" ")));
//		qDebug() << lower_value;
		if(lower_value.indexOf(tr(".")) == -1){
			lower_value += tr(".0");
		}

		vsf = new ValueSettingsForm(item, current_range, PM_BRANGE_ATTR, lower_value, upper_value);
		if(QDialog::Accepted == vsf->exec()){
			get_range = vsf->getRangeString();
			get_lower = vsf->getLowerValue();
			get_unit  = vsf->getUnitString();
			table->item(ProgTableDelegate::PROG_TABLE_ROW_BIAS_UNIT, c)->setText(get_range);
			table->item(ProgTableDelegate::PROG_TABLE_ROW_BIAS, c)->setText(get_lower + tr(" ") + get_unit);
		}
		delete vsf;

	}else if(ProgTableDelegate::PROG_TABLE_ROW_MEAS_L == r){
		current_range =
			table->item(ProgTableDelegate::PROG_TABLE_ROW_MEAS_UNIT, c)->text();
		lower_value = table->item(r, c)->text();
		upper_value = lower_value.left(lower_value.indexOf(tr(" ")));
		upper_value = upper_value.right(upper_value.length() - upper_value.indexOf("~") - 1);
		lower_value = lower_value.left(lower_value.indexOf(tr("~")));

		if(lower_value.indexOf(tr(".")) == -1){
			lower_value += tr(".0");
		}
		if(upper_value.indexOf(tr(".")) == -1){
			upper_value += tr(".0");
		}

		vsf = new ValueSettingsForm(item, current_range, PM_MRANGE_ATTR, lower_value, upper_value);
//		vsf = new ValueSettingsForm(item, current_range, PM_MRANGE_ATTR, tr("10"), tr("10"));
		if(QDialog::Accepted == vsf->exec()){
			get_range = vsf->getRangeString();
			get_lower = vsf->getLowerValue();
			get_unit  = vsf->getUnitString();
			get_upper = vsf->getUpperValue();
//			table->item(ProgTableDelegate::PROG_TABLE_ROW_BIAS_UNIT, c)->setText(get_range);
//			table->item(ProgTableDelegate::PROG_TABLE_ROW_BIAS, c)->setText(get_lower + tr(" ") + get_unit);
			table->item(ProgTableDelegate::PROG_TABLE_ROW_MEAS_L, c)->setText(get_lower + tr("~") + get_upper + tr(" ") + get_unit);
			table->item(ProgTableDelegate::PROG_TABLE_ROW_MEAS_UNIT, c)->setText(get_range);
		}
		delete vsf;
		
	}else{
		return;
	}
	
}

//
// 进入光量项目的detail设置界面
//
void ProgForm::detailSetting()
{
	//
	// 判断当前项目是否是光量项目，是否要进入设置界面
	//
	int currentCol	= table->currentColumn();
	int colCount	= table->columnCount();
	if(currentCol < 0 || currentCol > colCount - 1){ // 未选中任何item
		return;
	}

	QString itemNameSuffix = table->item(0, currentCol)->text();
	QString itemName = itemNameSuffix.left(itemNameSuffix.indexOf('_'));
	ushort code = 0;
	AprCfg::getParamCodeByName(itemName, PM_ITEM_ATTR, code);
	if(!AprCfg::isHueItem(code) && !itemName.contains(tr("DCC"))){
		return;
	}
	
	//
	// 运行detail设置对话框
	//
	if(itemName.contains(tr("DCC"))){
		updateEsdItemMap(currentCol);
	}

//	qDebug() << "after updateEsdItemMap()";	

	DetailDlg* dlg = new DetailDlg(itemNameSuffix, &hueDetail[currentCol], esdMap, this);
//	qDebug() << "after constructor of detail dlg";
	if(dlg->exec() == QDialog::Accepted){
		dlg->getHueDetail(&hueDetail[currentCol]);
/*
		qDebug() << "============== hue progform======================";
		qDebug() << hueDetail[currentCol].autorange;
		qDebug() << hueDetail[currentCol].ofstcancel;
		qDebug() << hueDetail[currentCol].mrng1;
		qDebug() << hueDetail[currentCol].scf1;
		qDebug() << hueDetail[currentCol].mrng2;
		qDebug() << hueDetail[currentCol].scf2;
		qDebug() << hueDetail[currentCol].mrng3;
		qDebug() << hueDetail[currentCol].scf3;
*/
	}
	delete dlg;	
}

void ProgForm::itemAdd()
{
	int insPos = table->columnCount();
	itemPosIns(insPos);
}

void ProgForm::itemInsert()
{
	int insPos = table->currentColumn();
	itemPosIns(insPos);

	// 查找所有dcc项目,改变其ref项目的index
	QString item;
	short ino = 0;
	for(int index = insPos+1; index < table->columnCount(); ++index){
		item = table->item(0, index)->text();
		if(item.contains(tr("DCC"))){
			ino = hueDetail[index].esd[0].ino;
			if(ino > insPos){
				hueDetail[index].esd[0].ino = ino+1;
			}

			ino = hueDetail[index].esd[1].ino;
			if(ino > insPos){
				hueDetail[index].esd[1].ino = ino+1;
			}
		}
	}

}

void ProgForm::itemDelete()
{
	int insPos = table->currentColumn();
	if(insPos < 0 || insPos > table->columnCount()){
		return;
	}

	//
	// 若此项目被一个dcc项目引用,在解除这种引用之前,不允许删除
	//
	bool removable = true;
	QString item = table->item(0, insPos)->text();
	short ino = 0;
	if(item.contains(tr("DCC")) || item.contains(tr("VF"))){
		for(int i = insPos+1; i < table->columnCount(); ++i){
			item = table->item(0, i)->text();
			if(item.contains(tr("DCC"))){
				ino = hueDetail[i].esd[0].ino;
				if((insPos+1)==ino){
					removable = false;
					break;
				}

				ino = hueDetail[i].esd[1].ino;
				if((insPos+1)==ino){
					removable = false;
					break;
				}
			}
		}
	}
	if(!removable){
		QMessageBox::warning(this, tr("CANNOT DELETE THIS ITEM"),
						  tr("THIS ITEM IS A REF ITEM OF A DCC ITEM!"));
		return;
	}

	handleDetailArray(insPos, false);
	
	//
	// delete all table items in the column
	//
	ProgTableItem *tableItem = NULL;
	for(int i = 0; i < PROG_TABLE_ROWS; ++i){
		tableItem = (ProgTableItem*)table->item(i, insPos);
		delete tableItem;
	} 
	table->removeColumn(insPos);
    table->setCurrentCell(0, table->columnCount());

	// 处理dcc的ref item的index
//	QString item;
//	short ino = 0;
	for(int index = insPos; index < table->columnCount(); ++index){
		item = table->item(0, index)->text();
		if(item.contains(tr("DCC"))){
			ino = hueDetail[index].esd[0].ino;
			if(ino > insPos){
				hueDetail[index].esd[0].ino = ino-1;
			}

			ino = hueDetail[index].esd[1].ino;
			if(ino > insPos){
				hueDetail[index].esd[1].ino = ino-1;
			}
		}
	}


	if(table->columnCount() == 0){
		deviceCombo->setEnabled(true);
	}
}

/*
void ProgForm::devTypeChanged()
{
	int		itemCnt 	= table->columnCount();
	bool	editable	= (0 == itemCnt);

	DevTypeSel dlg(editable, this);
	if(dlg.exec() == QDialog::Accepted){
		btnDevType->setText(dlg.strListDevType->at(dlg.devTypeIndex));

		chnCount = dlg.chnNum;
	}
}
*/

///////////////////////////////////////////////////////////////////////
////////// fuctions

// 建立可作为esd项目ref item的项目的map
void ProgForm::updateEsdItemMap(int dccIndex)
{
//	qDebug() << "update esd item map";
	QString itemNameSuffix;
	short ch = 1;
	short mapIndex = 0;	

	for(short index = 0; index < dccIndex; ++index){	
		itemNameSuffix = table->item(0, index)->text();
		ch = table->item(1, index)->text().toInt();
		if(itemNameSuffix.contains(tr("VF")) || itemNameSuffix.contains(tr("DCC"))){
			//esdMap[mapIndex] = { itemNameSuffix, ch, index+1 };
			esdMap[mapIndex].itemNameSuffix = itemNameSuffix;
			esdMap[mapIndex].ch = ch;
			esdMap[mapIndex].index = index+1;
			++mapIndex;
		}
	}

//	esdMap[mapIndex] = { tr(""), 0, -1 };
	esdMap[mapIndex].itemNameSuffix = tr("");
	esdMap[mapIndex].ch = 0;
	esdMap[mapIndex].index = -1;
}

QString ProgForm::checkNameSuffix(const QString& itemName)
{
	char suffixTable[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9',
						   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
						   'j', 'k', 'l', 'm', 'n', 'o', 'p' };

	QString itemNameSuffix;
	QString exist_item;
	bool bFind = true;
	for(int i = 0; i < MAX_ITEM_QTY; ++i){
		itemNameSuffix = itemName + "_" + suffixTable[i];
		bFind = true;
		for(int itemIndex = 0; itemIndex < table->columnCount(); ++itemIndex){
			if(table->item(0, itemIndex) == NULL){
				continue;
			}

			exist_item = table->item(0, itemIndex)->text();
			exist_item = exist_item.left(exist_item.indexOf(tr("(")));
//			if(table->item(0, itemIndex)->text() == itemNameSuffix){
			if(exist_item == itemNameSuffix){
				bFind = false;
				break;
			}
		}
		if(true == bFind){
			return itemNameSuffix;
		}
	}	
}

//=============================================================================
// func: 当有item插入，删除时，相应改变hueDetail序列
//
// param:
//		index - 被操作的item的index
//		bForward - 是否是向后移动array中的元素(插入操作),反之是删除操作。
//				   同时应注意：插入时要将新插入的item的detail初始化
//
//=============================================================================
void ProgForm::handleDetailArray(int index, bool bForward)
{
	bool esdItem = false;
	int refItemCount = 0;
	QString itemName = comboItemSel->currentText();
	if(itemName.contains(tr("DCC"))){
		esdItem = true;
		updateEsdItemMap(index);
		int i = 0;
		while(esdMap[i].index != -1){
			++i;
		}
		refItemCount = i;
	}

	if(bForward){	// 插入操作时
		//
		// 把原来在index之前(包括index)位置的元素后移
		// 最后一个被丢弃, 因为还能执行插入操作，说明最后一个item为空
		//
		// NOTE!: 当index为24时，下面循环不执行，那是因为此时的确不需要移动任何元素
		//        只需要将第24个item初始化即可
		for(int i = MAX_ITEM_QTY-1; i > index; --i){
			memcpy(&hueDetail[i], &hueDetail[i-1], sizeof(det_u));
		} 

		// 初始化新插入item的details
		if(esdItem){	// 演算项目,将最近的两个可ref项目ref到该dcc项目上
			ushort code = 0;
			hueDetail[index].esd[0].ino = esdMap[refItemCount-2].index;
			hueDetail[index].esd[0].ch  = esdMap[refItemCount-2].ch;
			QString itemNameSuffix = esdMap[refItemCount-2].itemNameSuffix;
			QString name = itemNameSuffix.left(itemNameSuffix.indexOf('_'));
		    char suffix = itemNameSuffix.at(itemNameSuffix.indexOf('_')+1).toAscii();
			AprCfg::getParamCodeByName(itemName, PM_ITEM_ATTR, code);
			hueDetail[index].esd[0].code = code;
			hueDetail[index].esd[0].suffix = suffix;

			hueDetail[index].esd[1].ino = esdMap[refItemCount-1].index;
			hueDetail[index].esd[1].ch  = esdMap[refItemCount-1].ch;
			itemNameSuffix = esdMap[refItemCount-1].itemNameSuffix;
			name = itemNameSuffix.left(itemNameSuffix.indexOf('_'));
			suffix = itemNameSuffix.at(itemNameSuffix.indexOf('_')+1).toAscii();
			AprCfg::getParamCodeByName(itemName, PM_ITEM_ATTR, code);
			hueDetail[index].esd[1].code = code;
			hueDetail[index].esd[1].suffix = suffix;
		}else{			// 光量项目
			hueDetail[index].hue.autorange = hueDetail[index].hue.ofstcancel = PM_OFF;
			hueDetail[index].hue.mrng1 = hueDetail[index].hue.mrng2 = hueDetail[index].hue.mrng3 = PM_H100_0nA;
			hueDetail[index].hue.scf1 = hueDetail[index].hue.scf2 = hueDetail[index].hue.scf3 = PM_HX1;
		}
	}else{	// 删除操作时
		for(int i = index; i < MAX_ITEM_QTY-1; ++i){
			memcpy(&hueDetail[i], &hueDetail[i+1], sizeof(det_u));
		}	
		
		// 清空第24个元素
		memset(&hueDetail[MAX_ITEM_QTY-1], 0xff, sizeof(det_u));
	}	
}

void ProgForm::itemPosIns(int insPos)
{
    // item count limit
    if(insPos > PROG_TABLE_MAX_COLS - 1 || insPos < 0){
        return;
    }

	// 处理detail相关数据的数组
	handleDetailArray(insPos, true);

	QStringList ranges;
	double 		upper;
	double 		lower;
	double 		step;
    ushort		decimals;

    //QComboBox	 	*combo;
    //QDoubleSpinBox 	*dspin;

	table->insertColumn(insPos);
	table->setColumnWidth(insPos, kColWidth);

	// ITEM NAME & SUFFIX & CHANNEL
	//QString item = comboItemSel->currentText();
	//char suffix = MeasProg::instance().getSuffix(item.toStdString());
	//QString item_suffix = item + suffix;
	QString itemSuffixName = checkNameSuffix(comboItemSel->currentText()) + tr("(1)");
	table->setItem(ProgTableDelegate::PROG_TABLE_ROW_NAME, insPos,
					new ProgTableItem(itemSuffixName));
//	table->setItem(ProgTableDelegate::PROG_TABLE_ROW_NAME, insPos,
//						 new ProgTableItem(comboItemSel->currentText()));
	
	// CHANNEL
//	table->setItem(ProgTableDelegate::PROG_TABLE_ROW_CHANNEL, insPos, 
//						new ProgTableItem("1"));

	//////////////////////////////////////////////////////////////////////
	///// BIAS RANGES
//	getRangesByItem(comboItemSel->currentText(), PM_BRANGE_ATTR, ranges);
//	getRangeDetailByName(ranges[0], PM_BRANGE_ATTR, upper, lower, step, decimals);
    AprCfg::getRangesByItem(
            comboItemSel->currentText(), PM_BRANGE_ATTR, ranges);
    AprCfg::getRangeDetailByName(
            ranges[0], PM_BRANGE_ATTR, upper, lower, step, decimals);

	ushort rng_code = 0;
	AprCfg::getParamCodeByName(ranges[0], PM_BRANGE_ATTR, rng_code);
//	const rng_tbl_s **range = NULL;
//	AprCfg::getRangeByCode(rng_code, *range);
//	qDebug() << range;
//	qDebug() << range->unit;
	const rng_tbl_s *range = AprCfg::getRangeByCode(rng_code);
	
	// BIAS
	table->setItem(ProgTableDelegate::PROG_TABLE_ROW_BIAS, insPos,
				new ProgTableItem(QString::number(lower) + tr(" ") + tr(range->unit)));		
//	qDebug() << range->unit;

	// BIAS UNIT
	table->setItem(ProgTableDelegate::PROG_TABLE_ROW_BIAS_UNIT,
				insPos, new ProgTableItem(ranges[0]));	

	// TIME
    //getRangeDetailByCode(PM_T9999ms, upper, lower, step, decimals);
    AprCfg::getRangeDetailByCode(PM_T9999ms, upper, lower, step, decimals);
	table->setItem(ProgTableDelegate::PROG_TABLE_ROW_TIME, insPos,
				new ProgTableItem(QString::number(lower)));

	///////////////////////////////////////////////////////////////////////
	///// MEAS RANGES
    AprCfg::getRangesByItem(
            comboItemSel->currentText(), PM_MRANGE_ATTR, ranges);
    AprCfg::getRangeDetailByName(
            ranges[0], PM_MRANGE_ATTR, upper, lower, step, decimals);
	AprCfg::getParamCodeByName(ranges[0], PM_MRANGE_ATTR, rng_code);
	range = AprCfg::getRangeByCode(rng_code);

	ProgTableItem *table_item = new ProgTableItem(QString::number(lower) + tr("~") + QString::number(upper) + tr(" ") + tr(range->unit));
//	QFont font;
//	font.setPointSize(10);
	QFont font = this->font();
	font.setPixelSize(font.pointSize() * 10 / 9);
	table_item->setFont(font);

	// MEAS LOWER LIMIT
	table->setItem(ProgTableDelegate::PROG_TABLE_ROW_MEAS_L, insPos, table_item);
//				new ProgTableItem(QString::number(lower) + tr(" ") + tr(range->unit)));

	// MEAS UPPER LIMIT
	table->setItem(ProgTableDelegate::PROG_TABLE_ROW_MEAS_U, insPos,
				new ProgTableItem(QString::number(upper) + tr(" ") + tr(range->unit)));

	// MEAS UNIT
	table->setItem(ProgTableDelegate::PROG_TABLE_ROW_MEAS_UNIT, insPos,
				new ProgTableItem(ranges[0]));

	// FILTER
	table->setItem(ProgTableDelegate::PROG_TABLE_ROW_FILTER, insPos,
				new ProgTableItem("OFF"));

	// VOLTAGE LIMIT
    AprCfg::getRangeDetailByCode(PM_L9_99V, upper, lower, step, decimals);
	table->setItem(ProgTableDelegate::PROG_TABLE_ROW_LIMIT, insPos,
				new ProgTableItem(QString::number(upper)));

	// LIMIT JUDGE
	table->setItem(ProgTableDelegate::PROG_TABLE_ROW_JUDGE, insPos,
						 new ProgTableItem("ON"));

	// ACTIVE
	table->setItem(ProgTableDelegate::PROG_TABLE_ROW_ACTIVE, insPos,
						 new ProgTableItem("ON"));

    table->setCurrentCell(0, table->columnCount());


	// device type should be able to be changed only when there is no any item
	deviceCombo->setEnabled(false);
}



void ProgForm::saveItems()
{
//	MeasProg mp = MeasProg::instance();
	MeasProg* pMeasProg = MeasProg::getInstance();

//	QString nameSuffix;
	QString name;
//	QString suffix;
	QString channel;
	QString waitTime;
	QString biasRange;
	QString biasValue;
	QString measRange;
	QString measUpper;
	QString measLower;
	QString volLimit;
	QString filOption;
	QString limitJudge;
	QString active;

	QString name_suffix_channel;
	QString bias_value_range, meas_value_range;
	for(int itemNo = 0; itemNo < table->columnCount(); ++itemNo){
	//	nameSuffix = table->item(ProgTableDelegate::PROG_TABLE_ROW_NAME, itemNo)->text();
	//	name = nameSuffix.left(nameSuffix.indexOf('_'));
	//	if(name.isEmpty()){
	//		break;
	//	}
	//	suffix = nameSuffix.right(nameSuffix.indexOf('_'));
//		name = table->item(ProgTableDelegate::PROG_TABLE_ROW_NAME, itemNo)->text();
//		channel = table->item(ProgTableDelegate::PROG_TABLE_ROW_CHANNEL, itemNo)->text();
		name_suffix_channel = table->item(ProgTableDelegate::PROG_TABLE_ROW_NAME, itemNo)->text();
		name = name_suffix_channel.left(name_suffix_channel.indexOf("("));
		channel = name_suffix_channel.right(name_suffix_channel.length() - name_suffix_channel.indexOf("(") - 1);
		channel = channel.left(1);
		qDebug() << "======= channel = " << channel;

//		qDebug() << "name_suffix_channel ===" << name << "," << channel;

		waitTime = table->item(ProgTableDelegate::PROG_TABLE_ROW_TIME, itemNo)->text();
		biasRange = table->item(ProgTableDelegate::PROG_TABLE_ROW_BIAS_UNIT, itemNo)->text();
//		biasValue = table->item(ProgTableDelegate::PROG_TABLE_ROW_BIAS, itemNo)->text();
		bias_value_range = table->item(ProgTableDelegate::PROG_TABLE_ROW_BIAS, itemNo)->text();
		biasValue = bias_value_range.left(bias_value_range.indexOf(tr(" ")));

		measRange = table->item(ProgTableDelegate::PROG_TABLE_ROW_MEAS_UNIT, itemNo)->text();
//		measUpper = table->item(ProgTableDelegate::PROG_TABLE_ROW_MEAS_U, itemNo)->text();
//		measLower = table->item(ProgTableDelegate::PROG_TABLE_ROW_MEAS_L, itemNo)->text();
		meas_value_range = table->item(ProgTableDelegate::PROG_TABLE_ROW_MEAS_L, itemNo)->text();
		measLower = meas_value_range.left(meas_value_range.indexOf(tr("~")));
		measUpper = meas_value_range.right(meas_value_range.length() - meas_value_range.indexOf(tr("~")) - 1);
		measUpper = measUpper.left(measUpper.indexOf(tr(" ")));
//		qDebug() << measLower << "," << measUpper << "," << measRange;


		volLimit = table->item(ProgTableDelegate::PROG_TABLE_ROW_LIMIT, itemNo)->text();
		filOption = table->item(ProgTableDelegate::PROG_TABLE_ROW_FILTER, itemNo)->text();
		limitJudge = table->item(ProgTableDelegate::PROG_TABLE_ROW_JUDGE, itemNo)->text();
		active = table->item(ProgTableDelegate::PROG_TABLE_ROW_ACTIVE, itemNo)->text();
/*
		qDebug() << " ProgForm::saveItems ================";
		qDebug() << " item" << itemNo << "================";
		qDebug() << name << "," << channel << "," << waitTime << "," << biasRange << "," 
				<< biasValue << "," << measRange << "," << measUpper << "," << measLower
				<< "," << volLimit << "," << filOption << "," << limitJudge << "," << active;
*/
		pMeasProg->setItem(itemNo, name, channel, waitTime, biasRange, biasValue, measRange,
					measUpper, measLower, volLimit, filOption, limitJudge, active, &hueDetail[itemNo]);
	}	

	pMeasProg->setProgItemCount(table->columnCount());

	// for debug BEGIN
//	program_s *p = pMeasProg->getProgPtr();
//	qDebug() << p->kinds[0].item[0].brange << "," << p->kinds[0].item[0].bvalue;
	// for debug END

/*
    LoadProgDlg *dlg = new LoadProgDlg();    // TODO:
	if(QDialog::Accepted == dlg->exec()){
		QString path =  dlg->getFilePath();
		pMeasProg->saveProgToFile(path);
//		emit progPathChanged(path); 
	}
	delete dlg;
*/

	
	SaveForm *dlg = new SaveForm;
	if(QDialog::Accepted == dlg->exec()){
		QString path =  dlg->getFilePath();
		pMeasProg->saveProgToFile(path);
	}
	delete dlg;

	program_s *prog = pMeasProg->getProgPtr();
//	ushort dev_index = 0;
//	AprCfg::getDevIndexByCode(prog->kinds[0].devicetyp, dev_index);
//	prog->kinds[0].deviceidx = dev_index;

	printf("prog.active is %hd\n",prog->active);
	printf("prog.ngcounton is %hd\n",prog->ngcounton);
	printf("prog.tonevolume is %hd\n",prog->tonevolume);
	printf("prog.altvolume is %hd\n",prog->altvolume);
	printf("prog.rangemode is %hd\n",prog->rangemode);
	printf("prog.kindno is %hd\n",prog->kindno);
	printf("prog.mmode is %hd\n",prog->mmode);
	printf("prog.ffs is %hd\n",prog->ffs);
	printf("prog.cntmode is %hd\n",prog->cntmode);
	printf("prog.filfreq is %hd\n",prog->filfreq);
	printf("prog.dliston is %hd\n",prog->dliston);
	printf("prog.tliston is %hd\n",prog->tliston);
	printf("prog.nondisp is %hd\n",prog->nondisp);
	printf("prog.autoseq is %hd\n",prog->autoseq);
	printf("prog.warn_ngcount is %hd\n",prog->warn_ngcount);
	printf("prog.hdr_logic is %hd\n",prog->hdr_logic);
	printf("prog.scan is %hd\n",prog->scan);
	printf("prog.endtime is %f\n",prog->endtime);
	printf("prog.offtime is %f\n",prog->offtime);
	printf("prog.dlm_k is %f\n",prog->dlm_k);
	printf("prog.serialno is %s\n",prog->serialno);
	printf("prog.kinds[0].active is %hd\n", prog->kinds[0].active);
	printf("prog.kinds[0].item[0].active is %hd\n", prog->kinds[0].item[0].active);
	printf("prog.kinds[0].item[0].limit is %hd\n", prog->kinds[0].item[0].limit);
	printf("prog.kinds[0].item[0].code is %hd\n", prog->kinds[0].item[0].code);
	printf("prog.kinds[0].item[0].suffix is %c\n", (char)prog->kinds[0].item[0].suffix);
	printf("prog.kinds[0].item[0].ch is %hd\n", prog->kinds[0].item[0].ch);
	printf("prog.kinds[0].item[0].waittime is %f\n", prog->kinds[0].item[0].waittime);
	printf("prog.kinds[0].item[0].brange is %hd\n", prog->kinds[0].item[0].brange);
	printf("prog.kinds[0].item[0].bvalue is %f\n", prog->kinds[0].item[0].bvalue);
	printf("prog.kinds[0].item[0].mrange is %hd\n", prog->kinds[0].item[0].mrange);
	printf("prog.kinds[0].item[0].mhilimit is %f\n", prog->kinds[0].item[0].mhilimit);
	printf("prog.kinds[0].item[0].mlowlimit is %f\n", prog->kinds[0].item[0].mlowlimit);
	printf("prog.kinds[0].item[0].vlimit is %f\n", prog->kinds[0].item[0].vlimit);
	printf("prog.kinds[0].item[0].filter is %hd\n", prog->kinds[0].item[0].filter);
	printf("prog.kinds[0].item[0].outsig is %hd\n", prog->kinds[0].item[0].outsig);
	printf("prog.kinds[0].item[0].insig is %hd\n", prog->kinds[0].item[0].insig);
	printf("prog.kinds[0].devicetyp is %hd\n", prog->kinds[0].devicetyp);
}

void ProgForm::loadItems()
{
//	MeasProg mp = MeasProg::instance();
	MeasProg* pMeasProg = MeasProg::getInstance();
//	pMeasProg->readProgFromFile(path);

	program_s* p = pMeasProg->getProgPtr();
	QString strDev;
	AprCfg::getParamNameByCode(p->kinds[0].devicetyp, strDev);
	chnCount = strDev.left(1).toInt();
//	printf("prog.kinds[0].devicetyp is %hd\n", p->kinds[0].devicetyp);
//	btnDevType->setText(strDev);		
	int dev_index = deviceCombo->findText(strDev);
	deviceCombo->setCurrentIndex(dev_index);
	if(p->item_total != 0){
		deviceCombo->setEnabled(false);
	}


//	qDebug() << mp.getProgItemCount();	

	QString name;
	QString channel;
	QString waitTime;
	QString biasRange;
	QString biasValue;
	QString measRange;
	QString measUpper;
	QString measLower;
	QString volLimit;
	QString filOption;
	QString limitJudge;
	QString active;

//	for(int col = 0; col < table->columnCount(); ++col){
//		table->removeColumn(col);
//	}
	while(table->columnCount() > 0){
		table->removeColumn(0);
	}

	for(int itemCnt = 0; itemCnt < pMeasProg->getProgItemCount(); ++itemCnt){
		table->insertColumn(0);
		table->setColumnWidth(0, kColWidth);
	}
	
	det_u det;

	ushort range_code = 0;
	const rng_tbl_s *range = NULL;
	QString bias_unit, meas_unit;
	ProgTableItem *table_item = NULL;
//	QFont font;
//	font.setPointSize(10);
	QFont font = this->font();
	font.setPixelSize(font.pointSize() * 10 / 9);
//	table_item->setFont(font);
	for(int itemNo = 0; itemNo < pMeasProg->getProgItemCount(); ++itemNo){
		pMeasProg->getItem(itemNo, name, channel, waitTime, biasRange, biasValue, measRange,
				measUpper, measLower, volLimit, filOption, limitJudge, active, &det);

		table->setItem(ProgTableDelegate::PROG_TABLE_ROW_NAME, itemNo, new ProgTableItem(name + tr("(") + channel + tr(")")));
//		table->setItem(ProgTableDelegate::PROG_TABLE_ROW_CHANNEL, itemNo, new ProgTableItem(channel));
		table->setItem(ProgTableDelegate::PROG_TABLE_ROW_TIME, itemNo, new ProgTableItem(waitTime));
		table->setItem(ProgTableDelegate::PROG_TABLE_ROW_BIAS_UNIT, itemNo, new ProgTableItem(biasRange));

		AprCfg::getParamCodeByName(biasRange, PM_BRANGE_ATTR, range_code);
		range = AprCfg::getRangeByCode(range_code);
		table->setItem(ProgTableDelegate::PROG_TABLE_ROW_BIAS, itemNo, new ProgTableItem(biasValue + tr(" ") + range->unit));
		table->setItem(ProgTableDelegate::PROG_TABLE_ROW_MEAS_UNIT, itemNo, new ProgTableItem(measRange));
		table->setItem(ProgTableDelegate::PROG_TABLE_ROW_MEAS_U, itemNo, new ProgTableItem(measUpper));

		AprCfg::getParamCodeByName(measRange, PM_MRANGE_ATTR, range_code);
		range = AprCfg::getRangeByCode(range_code);
		table_item = new ProgTableItem(measLower + tr("~") + measUpper + tr(" ") + range->unit);
		table_item->setFont(font);
		table->setItem(ProgTableDelegate::PROG_TABLE_ROW_MEAS_L, itemNo, table_item);
		table->setItem(ProgTableDelegate::PROG_TABLE_ROW_LIMIT, itemNo, new ProgTableItem(volLimit));
		table->setItem(ProgTableDelegate::PROG_TABLE_ROW_FILTER, itemNo, new ProgTableItem(filOption));
		table->setItem(ProgTableDelegate::PROG_TABLE_ROW_JUDGE, itemNo, new ProgTableItem(limitJudge));
		table->setItem(ProgTableDelegate::PROG_TABLE_ROW_ACTIVE, itemNo, new ProgTableItem(active));
		memcpy(&hueDetail[itemNo], &det, sizeof(det_u));

/*
		table->item(ProgTableDelegate::PROG_TABLE_ROW_NAME, itemNo)->setText(name);	
		table->item(ProgTableDelegate::PROG_TABLE_ROW_CHANNEL, itemNo)->setText(channel);	
		table->item(ProgTableDelegate::PROG_TABLE_ROW_TIME, itemNo)->setText(waitTime);	
		table->item(ProgTableDelegate::PROG_TABLE_ROW_BIAS_UNIT, itemNo)->setText(biasRange);	
		table->item(ProgTableDelegate::PROG_TABLE_ROW_BIAS, itemNo)->setText(biasValue);	
		table->item(ProgTableDelegate::PROG_TABLE_ROW_MEAS_UNIT, itemNo)->setText(measRange);	
		table->item(ProgTableDelegate::PROG_TABLE_ROW_MEAS_U, itemNo)->setText(measUpper);	
		table->item(ProgTableDelegate::PROG_TABLE_ROW_MEAS_L, itemNo)->setText(measLower);	
		table->item(ProgTableDelegate::PROG_TABLE_ROW_LIMIT, itemNo)->setText(volLimit);	
		table->item(ProgTableDelegate::PROG_TABLE_ROW_FILTER, itemNo)->setText(filOption);	
		table->item(ProgTableDelegate::PROG_TABLE_ROW_JUDGE, itemNo)->setText(limitJudge);	
		table->item(ProgTableDelegate::PROG_TABLE_ROW_ACTIVE, itemNo)->setText(active);	
*/
	}
}



void ProgForm::clearItems()
{
	while(table->columnCount() > 0){
		table->setCurrentCell(0, 0);	
//		table->removeColumn(0);
		itemDelete();
	}

	MeasProg* pMeasProg = MeasProg::getInstance();
	program_s* p = pMeasProg->getProgPtr();

//	for(int itemIndex = 0; itemIndex < p->item_no; ++itemIndex){
	for(int itemIndex = 0; itemIndex < p->item_total; ++ itemIndex){
		p->kinds[0].item[itemIndex].active = -1;
	}
	
//	p->item_no = 0;
	p->item_total = 0;

	deviceCombo->setEnabled(true);
}

void ProgForm::createProg()
{
	// TODO: init DEV TYPE & clear current prog path

	clearItems();
}


/*
void ProgForm::openDevTypeDlg()
{
	bool mod = table->columnCount() == 0;

	QString str = btnDevType->text();
	DevTypeSel* dlg = new DevTypeSel(mod, str, this);
	if(QDialog::Accepted == dlg->exec()){
		chnCount = dlg->chnNum;
		btnDevType->setText(dlg->currentDev);	
	}
	
	delete dlg;
}
*/


void ProgForm::itemKindSel(const QString& text)
{
	btnItemAdd->setEnabled(true);
	btnItemIns->setEnabled(true);

	if(text.contains(tr("DCC"))){	// 若是dcc,则要检查是否有两个以上vf项目
		int index = 0;
		int itemCount = table->columnCount();
		int findCount = 0;
		QString itemName;
//		for( ; index < itemCount; ++index)
		while(index < itemCount){
			itemName = table->item(0, index)->text();
			if(itemName.contains(tr("VF"))){
				++findCount;
			}
			++index;
		}
		
		if(findCount < 2){
			btnItemAdd->setEnabled(false);
			btnItemIns->setEnabled(false);	
		}
	}
}




void ProgForm::deviceTypeChanged(const QString& text)
{
	QString chn_str = text.left(1);
	chnCount = chn_str.toInt();

	MeasProg* pMeasProg = MeasProg::getInstance();
	program_s* p = pMeasProg->getProgPtr();
//	QString strDev;
//	AprCfg::getParamNameByCode(p->kinds[0].devicetyp, strDev);
	ushort dev_code = 0;
	AprCfg::getParamCodeByName(text, PM_DEV_ATTR, dev_code);
	p->kinds[0].devicetyp = dev_code;
//	p->kinds[0].deviceidx =
	ushort index = 0;
	AprCfg::getDevIndexByCode(dev_code, index);
	p->kinds[0].deviceidx = index;

}


void ProgForm::formShouldReturn()
{
	// TODO: 判断是否保存改动

	delete this;
}
